﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace CPlase
{
    public static class Alphabet
    {
        /// <summary>
        /// 62-буквенный алфавит с сортированными символами [0-9A-Za-z]
        /// </summary>
        public const string STANDARD62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        public const int STANDARD62_LENGTH = 62;

        public const char FIRST_CHAR = '0';
        public const char LAST_CHAR = 'z';

        /// <summary>
        /// 67-буквенный алфавит с НЕ сортированными символами [0-9A-Za-z ,-.@]
        /// </summary>
        public const string EXTENDED67 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ,-.@";
    }

    public static class NumericNotations
    {
        public static int GetCategoryExtended(char Char)
        {
            return Alphabet.EXTENDED67.IndexOf(Char);
        }

        public static char GetDigitExtended(int Index)
        {
            return Alphabet.EXTENDED67[Index];
        }

        public static string Convert(string SourceNumber, int SourceScaleOfNotation, int TargetScaleOfNotation, byte CountChars = 11)
        {
            if (SourceNumber == null || SourceNumber == "") throw new NullReferenceException("SourceNumber cant be null or empty");
            if (SourceScaleOfNotation == TargetScaleOfNotation) return "00000000000".Substring(0, 11 - SourceNumber.Length) + SourceNumber;
            long DecimalNumber = Decimal(SourceNumber, SourceScaleOfNotation);
            return Convert(DecimalNumber, TargetScaleOfNotation, CountChars);
        }

        public static long Decimal(string SourceNumber, int SourceScaleOfNotation)
        {
            int Len = SourceNumber.Length;
            long Result = 0;
            for (int i = 1; i <= Len; i++)
            {
                int CurrentDigitCategory = i - 1;
                char CurrentDigit = SourceNumber[Len - i];
                int Digit = Alphabet.STANDARD62.IndexOf(CurrentDigit);
                if (Digit < 0 || Digit >= SourceScaleOfNotation) throw new ArgumentOutOfRangeException("Unsupportable digit");
                if (Digit > 0)
                {
                    long Category = 1;
                    for (int Iterator2 = 0; Iterator2 < CurrentDigitCategory; Iterator2++)
                    {
                        Category *= SourceScaleOfNotation;
                    }
                    Result += Category * Digit;
                }
            }

            return Result;
        }

        public static string Convert(long SourceNumber, int TargetScaleOfNotation, byte CountChars = 11)
        {
            int Iterator = 0;
            int CurrentDigitCategory = 0;
            byte[] DigitsBytes = new byte[CountChars];
            for (Iterator = 1; Iterator < CountChars + 1; Iterator++)
            {
                CurrentDigitCategory = CountChars - Iterator;
                long SourceSubtraction = 1;
                for (int Iterator2 = 0; Iterator2 < CurrentDigitCategory; Iterator2++)
                {
                    SourceSubtraction *= TargetScaleOfNotation;
                }
                byte DigitByte = (byte)((SourceNumber - (SourceNumber % SourceSubtraction)) / SourceSubtraction);
                SourceNumber -= (long)(DigitByte * SourceSubtraction);
                DigitsBytes[Iterator - 1] = DigitByte;
            }
            string ResultNumber = "";
            for (Iterator = 0; Iterator < CountChars; Iterator++)
            {
                ResultNumber += Alphabet.STANDARD62[DigitsBytes[Iterator]];
            }

            return ResultNumber;
        }
    }
}